package com.icesoft.core.web.helper.http;

import com.fasterxml.jackson.core.type.TypeReference;
import com.icesoft.core.common.helper.Resp;
import com.icesoft.core.common.util.JsonUtil;
import com.icesoft.core.common.util.UuidUtil;
import com.icesoft.core.web.model.CryptoPublicKey;
import com.icesoft.core.web.suppose.safehttp.SafeRequestConst;
import com.icesoft.core.web.suppose.safehttp.service.ICryptoService;
import com.icesoft.core.web.suppose.safehttp.service.impl.RsaAesCryptoService;
import com.icesoft.core.web.suppose.safehttp.service.impl.Sm2Sm4CryptoService;
import lombok.Setter;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.web.client.RestTemplate;

import java.util.Map;
import java.util.TreeMap;

public class SafeRequestHttpHelp {

    private final Map<String, String> params = new TreeMap<>();
    private final Map<String, String> headers = new TreeMap<>();
    private String sign;
    @Setter
    private String publicKeyUrl;
    @Setter
    private String url;
    @Setter
    private RestTemplate restTemplate;
    @Setter
    private ICryptoService cryptoService;
    @Setter
    private CryptoPublicKey cryptoKey;

    /**
     * 加密接口工具
     *
     * @param baseUrl 项目地址，以“/”结尾
     * @param uri     不带项目地址接口路径，不带“/”开头
     */
    public static SafeRequestHttpHelp builder(String baseUrl, String uri) {
        SafeRequestHttpHelp appRequestHelp = new SafeRequestHttpHelp();
        appRequestHelp.publicKeyUrl = baseUrl + "public/crypto/publicKey";
        appRequestHelp.url = baseUrl + uri;
        return appRequestHelp;
    }

    public SafeRequestHttpHelp param(String name, String value) {
        params.put(name, value);
        return this;
    }

    public SafeRequestHttpHelp params(Map<String, String> userParams) {
        params.putAll(userParams);
        return this;
    }

    public SafeRequestHttpHelp token(String token) {
        return header("token", token);
    }

    public SafeRequestHttpHelp header(String name, String value) {
        headers.put(name, value);
        return this;
    }

    public SafeRequestHttpHelp headers(Map<String, String> headerPar) {
        headers.putAll(headerPar);
        return this;
    }

    /**
     * post请求
     * 解密处理过的数据
     */
    public <T> Resp<T> post(TypeReference<Resp<T>> responseType) {
        return new SafeRequestResult(fastRestTemplatePost(), sign, cryptoService).toResp(responseType);
    }

    private String fastRestTemplatePost() {
        initData();
        String body = JsonUtil.toJson(params);
        body = cryptoService.symmetricEncrypt(sign, body);
        return FastRestTemplate.builder(url, body).restTemplate(restTemplate).addHeaders(headers).post();
    }

    private void initData() {
        if (cryptoKey == null) {
            cryptoKey = getRemoteCryptoKey();
        }
        if (cryptoService == null) {
            if (SafeRequestConst.ALGORITHM_SM.equals(cryptoKey.getAlgorithm())) {
                cryptoService = new Sm2Sm4CryptoService();
            } else {
                cryptoService = new RsaAesCryptoService();
            }
        }
        String nonceStr = UuidUtil.get32UUID();
        String timeUnit = String.valueOf(System.currentTimeMillis());
        params.putIfAbsent("nonceStr", nonceStr);
        params.putIfAbsent("timeUnit", timeUnit);

        sign = SignUtil.sign(params);
        String signRsa = cryptoService.publicEncrypt(cryptoKey.getPublicKey(), sign);
        headers.put(SafeRequestConst.HEAD_SIGN_PARAM_NAME, signRsa);
        headers.put(SafeRequestConst.HEAD_KEY_ID_PARAM_NAME, cryptoKey.getKeyId());
        headers.putIfAbsent("versionCode", "2");
        headers.put("clientType", "SafeRequestHttpHelp");
    }

    private CryptoPublicKey getRemoteCryptoKey() {
        return FastRestTemplate.builder(publicKeyUrl).get(new ParameterizedTypeReference<Resp<CryptoPublicKey>>() {
        }).getData();
    }
}
